### 懒人创建工程
## 统一递归的包含源文件、头文件 然后在编译一股脑的全部编译即可
## 或者递归的查找当前文件夹下的所有文件夹，递归添加所有文件夹
## 但是这样后发现，添加头文件需要用相对路径，这样就显得麻烦了，所以还是直接将头文件所在的文件夹声明好


# 设置CMake的最低版本要求
cmake_minimum_required(VERSION 3.5)

# 设置项目名称
project(CDataStructProject)
message(STATUS "Build CDataStructProject ......")
message(STATUS "CMAKE_CURRENT_SOURCE_DIR is ${CMAKE_CURRENT_SOURCE_DIR}")
# 检查编译宏定义是否为空，给一个默认的宏定义
if (NOT DEFINED PROJECT_DEBUG)
    message(STATUS "PROJECT_DEBUG = LISTDOUBLELINK_DEBUG")
    add_definitions(-DLISTDOUBLELINK_DEBUG)
endif ()

# 添加宏定义 这个是cmake的条件编译 在cmake ..阶段就会条件编译源文件 而不是在make阶段
# add_definitions(-DROUND_QUEUE_DEBUG)


# 设置交叉编译工具链
#set(CMAKE_C_COMPILER "/usr/bin/arm-none-eabi-gcc")
#set(CMAKE_CXX_COMPILER "/usr/bin/arm-none-eabi-g++")
set(CMAKE_C_COMPILER "/usr/bin/gcc")
set(CMAKE_CXX_COMPILER "/usr/bin/g++")

# 指定源文件路径
# set(SRC QuickSort.c)
# aux_source_directory(${PROJECT_SOURCE_DIR}/Src SRC)       # PROJECT_SOURCE_DIR 执行cmkae ..时的..

# 手动添加忽略文件
set(IGNORE_FILES ".*Build.*" ".*git.*")

# message(STATUS "IGNORE_FILE = ${IGNORE_FILES}")
# foreach(ignore_dir ${IGNORE_FILES})
#     string(REGEX MATCH ${ignore_dir} ignore_index "/home/qd/Desktop/Workplace/Projects/CommonDataStruct/CDataStruct/Build/CMakeFiles/Progress")
#     if (NOT ignore_index) # 如果路径中不存在git字符
#         message(STATUS "ignore_index = ${ignore_index}")
#     endif()
# endforeach() 
# message(FATAL_ERROR "====== ignore_index = ${ignore_index}")



# 定义函数，用于递归添加头文件 参考：https://blog.csdn.net/lqz790192593/article/details/112389034
function(include_sub_directories_recursively root_dir)
    set(ALL_IGNORE_FILE_UNMATCH TRUE) # 所有的匹配模式都不匹配才将其记录到SRC中

    if (IS_DIRECTORY ${root_dir})               # 当前路径是一个目录吗，是的话就加入到包含目录
        # list(FIND IGNORE_FILES ${root_dir} ignore_index)    # 检查 ${root_dir} 是否在 IGNORE_FILE 中 是就返回对应的索引
        foreach(ignore_dir ${IGNORE_FILES})
        # message("ignore_dir = ${ignore_dir}")
            string(REGEX MATCH ${ignore_dir} ignore_index ${root_dir})
            
            if ( ignore_index)
                set(ALL_IGNORE_FILE_UNMATCH FALSE)
                break()
            else()
                
            endif()
        endforeach() 

        if (ALL_IGNORE_FILE_UNMATCH)
            # message(STATUS "include dir: ${root_dir}")
            include_directories(${root_dir})
        endif()
        
        # if (NOT ${root_dir} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}/Build/CmakeFiles)   # 检查文件名是否为Build
        # endif()
    endif()
 
    file(GLOB ALL_SUB RELATIVE ${root_dir} ${root_dir}/*) # 获得当前目录下的所有文件，让如ALL_SUB列表中
    foreach(sub ${ALL_SUB})
        if (IS_DIRECTORY ${root_dir}/${sub})
            include_sub_directories_recursively(${root_dir}/${sub}) # 对子目录递归调用，包含
        endif()
    endforeach()

endfunction()

include_sub_directories_recursively(${CMAKE_CURRENT_SOURCE_DIR}) # 对子目录递归调用，包含

## 使用查找源文件并添加的形式，防止每增加一个文件夹都要添加一次文件夹路径
# file(GLOB SRC ${CMAKE_CURRENT_SOURCE_DIR}/*c)             # GLOB 不进行地柜搜索 CMAKE_CURRENT_SOURCE_DIR CMakeLists.txt的路径
file(GLOB_RECURSE SRC_FILE ${CMAKE_CURRENT_SOURCE_DIR}/*.c)    # 递归的查找并添加源文件

# 指定头文件路径 这样在包含头文件时，就不需要以CMakeLists.txt文件所在的目录问根文件来做相对路径
# include_directories(${PROJECT_SOURCE_DIR}/Include)

## 使用查找头文件并添加的形式，防止每增加一个文件夹都要添加一次文件夹路径
file(GLOB_RECURSE HEADER_FILE ${CMAKE_CURRENT_SOURCE_DIR}/*.h)


# 指定可执行程序路径 后期也可指定编译出的库的路径
# set(EXECUTABLE_OUTPUT_PATH ./)

# 指定C++标准
# set(CMAKE_CXX_STANDARD 11)

# 生成动态库 SHARED 有可执行权限; 静态库 STATIC 无可执行权限
# 发布时需要将库+头文件发布一起发布出去
# add_library(CMakeLearning SHARED ${SRC})

# 指定生成库文件路径
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/Libs)

# 链接静态库 可以掐头去尾;静态库会被打包到对应的可执行程序中,动态库不会
# link_libraries(libCMakeLearning.a)
# 指定库路径
# link_directories(${PROJECT_SOURCE_DIR}/Libs)

# 过滤掉CMakeFiles中的不用的文件 感觉这样不严谨 应该还要写一个=过滤函数，只要是Build目录下的源文件都不能加入
list(REMOVE_ITEM SRC_FILE ${CMAKE_CURRENT_SOURCE_DIR}/Build/CMakeFiles/feature_tests.c ${CMAKE_CURRENT_SOURCE_DIR}/Build/CMakeFiles/3.5.2/CompilerIdC/CMakeCCompilerId.c)
list(REMOVE_ITEM SRC_FILE  ${CMAKE_CURRENT_SOURCE_DIR}/cmake-build-cdatastruct/CMakeFiles/3.27.0/CompilerIdC/CMakeCCompilerId.c)

message(STATUS "SRC_FILE = ${SRC_FILE}")

# 遍历文件路径列表，将文件名提取出来
foreach(SRC_FILE_PATH ${SRC_FILE})
    get_filename_component(SRC_FILE_NAME ${SRC_FILE_PATH} NAME)
    list(APPEND SRC_FILE_NAMES ${SRC_FILE_NAME})
endforeach()
foreach(HEADER_FILE_PATH ${HEADER_FILE})
    get_filename_component(HEADER_FILE_NAME ${HEADER_FILE_PATH} NAME)
    list(APPEND HEADER_FILE_NAMES ${HEADER_FILE_NAME})
endforeach(HEADER_FILE_PATH ${HEADER_FILE})

message(STATUS "SRC_FILE_NAMES    = ${SRC_FILE_NAMES}")
message(STATUS "HEADER_FILE_NAMES = ${HEADER_FILE_NAMES}")


# 添加可执行文件
add_executable(CDataStruct ${SRC_FILE} ${HEADER_FILE}
        Global/type_redefine.h)

# cmake ..时指定即可cmake -DPROJECT_DEBUG=ROUND_QUEUE_DEBUG .. 这样就可以将cmake时定义的条件编译传递到源文件中使源文件也可以条件编译
message(STATUS "PROJECT_DEBUG = ${PROJECT_DEBUG}")
target_compile_definitions(CDataStruct PRIVATE ${PROJECT_DEBUG})
